<?php

/**
 * @author b3ha
 * based on http://devzone.zend.com/article/2855
 */
class Controller_Action extends Zend_Controller_Action
{
    protected $inPost   = NULL;
    protected $inGet    = NULL;
    
    protected $userId   = NULL;
    protected $userName = NULL;
    
    public function init()
    {
        parent::init();
        
        $appname = basename(dirname(APPLICATION_PATH));
        
        // handle stuffs
        $this->handleAjaxRequest();
        
        // initialize Session
        $this->_initSession();
        
        // Template assigns
        $this->view->assets     = "/{$appname}/application/assets";
        $this->view->assetsCss  = "/{$appname}/application/assets/css";
        $this->view->assetsJs   = "/{$appname}/application/assets/js";
        $this->view->assetsLib  = "/{$appname}/application/assets/library";
        $this->view->assetsPic  = "/{$appname}/application/assets/pic";
        $this->view->serverProt = ($_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1') ? 'http':'https';
        $this->view->serverName = $_SERVER['SERVER_NAME'];
        $this->view->baseDir    = ZReg::get('serPaths')->baseDir;
        $this->view->serverSpec = "{$this->view->serverProt}://{$this->view->serverName}{$this->view->baseDir}";
        
        $this->view->controller = $this->getRequest()->getControllerName();
        $this->view->action     = $this->getRequest()->getActionName();
        
        if (Zend_Session::sessionExists() &&
            Zend_Session::namespaceIsset('user'))
        {
            $sessionUser = Zend_Session::namespaceGet('user');
            $this->view->userId         = $sessionUser['id'];
            $this->view->userUserName   = $sessionUser['userName'];
            $this->view->userName       = $sessionUser['name'];
            
            $this->userId               = $sessionUser['id'];
            $this->userName             = $sessionUser['userName'];
        }
        
        // Post and Get values (filtered)
        $inPost = new Zend_Filter_Input(array('*' => 'StripTags'), array(), $_POST);
        $this->view->inPost = $this->inPost = $inPost->getEscaped();
        $inGet = new Zend_Filter_Input(array('*' => 'StripTags'), array(), $_GET);
        $this->view->inGet = $this->inGet = $inGet->getEscaped();
    }
    
    /**
     * initialize Session
     */
    private function _initSession()
    {   
        Zend_Session::setOptions(ZReg::get('config')->session->toArray());
        
        $request = $this->getRequest();
        
        // if user is not at auth module and theres no session cookie
        if ('auth'  !== $request->getControllerName() &&
            ! Zend_Session::sessionExists())
        {
            $this->_helper->getHelper('Redirector')->gotoUrl('/auth/login');
        }
        // if theres a session cookie
        elseif (Zend_Session::sessionExists())
        {
            if ( ! Zend_Session::isStarted()) Zend_Session::start();
            
            // theres no user session
            if ( ! Zend_Session::namespaceIsset('user'))
            {
                Zend_Session::destroy(TRUE);
                if ('auth'  !== $request->getControllerName() &&
                    'logout' !== $request->getActionName())
                $this->_helper->getHelper('Redirector')->gotoUrl('/auth/logout');
            }
            else
            {
                $sessionUser    = Zend_Session::namespaceGet('user');
                $extraTokenName = ZReg::get('config')->sessionExtra->tokenName;
                $extraToken     = $request->getCookie($extraTokenName);
                // theres no token at client/server side or its wrong
                if ( ! isset($extraToken) ||
                     ! isset($sessionUser[$extraTokenName]) ||
                    $extraToken !== $sessionUser[$extraTokenName])
                {
                    Zend_Session::destroy(TRUE);
                    if ('auth'  !== $request->getControllerName() &&
                        'logout' !== $request->getActionName())
                    $this->_helper->getHelper('Redirector')->gotoUrl('/auth/logout');
                }
            }
        }
        
        // everything is okey, but if we at auth...
        if ('auth'  === $request->getControllerName() &&
            'logout' !== $request->getActionName() &&
            Zend_Session::sessionExists())
            $this->_helper->getHelper('Redirector')->gotoUrl('/events');
    }
    
    /**
     * Dispatch the requested action, override to handle action parameters
     * 
     * @param string $action Method name of action
     */
    public function dispatch($action)
    {   
        //----------------------------------------------------------------------
        // action with parameters

        // Get all request parameters
        $params = $this->
                    getRequest()->
                        getQuery() ? : $this->getRequest()->getUserParams();

        // Create data array
        $data = array();
        foreach ($this->getMethodParameters($action) as $mp)
        {
            $name = $mp->getName();
            
            if ($mp->isOptional())
            {
                $data[$name] =  isset($params[$name]) ?
                                $params[$name] :
                                $mp->getDefaultValue();
            }
            else if ( ! isset($params[$name]))
            {
                throw new InvalidArgumentException("Parameter <{$name}> not set!");
            }
            else
            {
                $data[$name] = $params[$name];
            }
        }
        
        // Notify helpers of action preDispatch state
        $this->_helper->notifyPreDispatch();

        $this->preDispatch();
        if ($this->getRequest()->isDispatched()) 
        {
            if (null === $this->_classMethods)
            {
                $this->_classMethods = get_class_methods($this);
            }

            // If pre-dispatch hooks introduced a redirect then stop dispatch
            // @see ZF-7496
            if (!($this->getResponse()->isRedirect()))
            {
                // preDispatch() didn't change the action, so we can continue
                if ($this->getInvokeArg('useCaseSensitiveActions') ||
                    in_array($action, $this->_classMethods))
                {
                    if ($this->getInvokeArg('useCaseSensitiveActions'))
                    {
                        trigger_error(
                            'Using case sensitive actions without word '.
                            'separators is deprecated; please do not '.
                            'rely on this "feature"');
                    }
                    call_user_func_array(array($this, $action), $data);
                }
                else
                {
                    $this->__call($action, $data);
                }
            }
            $this->postDispatch();
        }

        // whats actually important here is that this action controller is
        // shutting down, regardless of dispatching; notify the helpers of this
        // state
        $this->_helper->notifyPostDispatch();
    }
    
    protected function getMethodParameters($action)
    {
        $r = new ReflectionMethod(get_class($this), $action);

        return $r->getParameters();
    }
    
    protected function handleAjaxRequest()
    {
        if ($this->_request->isXmlHttpRequest())
        {
            $this->_helper->removeHelper('viewRenderer');
        }
    }
    
    protected function getPost($name)
    {
        return $this->getRequest()->getPost($name);
    }
    
    public function filterInput(array $filters, 
                                array $validators,
                                array $userInput,
                                $csrf = TRUE,
                                array &$messages = array())
    {   
        $input = new Zend_Filter_Input($filters, $validators, $userInput);
        
        if ($input->hasInvalid() || $input->hasMissing())
        {
            $this->view->errForm = $input->getMessages();
            $messages = $input->getMessages();
            
            $this->createCSRFToken();
            return FALSE;
        }
        elseif ($csrf &&
                Zend_Registry::get('user')->csrfToken !== $this->getPost('csrfToken'))
        {
            return FALSE;
        }
        
        $this->createCSRFToken();
        return TRUE;
    }
    
    public function createCSRFToken()
    {
        Zend_Registry::get('user')->csrfToken = uniqid();
        $this->view->csrfToken = Zend_Registry::get('user')->csrfToken;
    }
}
